#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QTextCursor>
#include <QMessageBox>
#include <QMovie>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QMovie *mov = new QMovie(":/RightArrow.gif");
    mov->setScaledSize(ui->ADLabel->size());
    mov->start();
    ui->ADLabel->setMovie(mov);

    comPort = new Serial();
    connect(comPort, SIGNAL(readDone()), this, SLOT(serialReadDone()));
    QString serialName;
    foreach (serialName, comPort->serialPortList) {
        ui->serialSelectComboBox->addItem(serialName);
    }

    sock = new NetSocket();
    connect(sock, SIGNAL(socketChanged()), this, SLOT(socketCountUpdate()));
    connect(sock, SIGNAL(readDone()), this, SLOT(socketReadDone()));
}

MainWindow::~MainWindow()
{
    delete ui;

    if (comPort != Q_NULLPTR)
        delete comPort;

    if (sock != Q_NULLPTR) {
        delete sock;
    }
}

// Hex display to Hex data
QByteArray MainWindow::charToHex(QByteArray chr)
{
    QByteArray tempHex = chr.toHex().toUpper();
    QByteArray resultHex;

    for (int i = 0; i < tempHex.length() / 2; i++) {
        resultHex += tempHex.mid(i * 2, 2) + " ";
    }

    return resultHex;
}

QByteArray MainWindow::senderToHex(QByteArray sender)
{
    QByteArray src = sender.toUpper();
    QByteArray tempBuf;
    unsigned char dat = 0;
    int count = 0;

    for (int i = 0; i < src.length(); i++) {
        count++;
        if ((src[i] >= '0') && (src[i] <= '9')) {
            dat |= src[i] - '0';
        } else if ((src[i] >= 'A') && (src[i] <= 'F')) {
            dat |= src[i] - 'A' + 10;
        } else {
            if (count == 2) {
                dat >>= 4;
                tempBuf.append(dat);
            }
            count = 0;
            dat = 0;
            continue;
        }

        if (count < 2) {
            dat <<= 4;
        } else {
            tempBuf.append(dat);
            count = 0;
            dat = 0;
        }
    }
    if (count == 1) {
        dat >>= 4;
        tempBuf.append(dat);
    }

    return tempBuf;
}

// Char to Hex ASCII String
QByteArray MainWindow::displayCharToHex(QByteArray chr)
{
    return chr.toHex(' ');
}

QByteArray MainWindow::displayHexToChar(QByteArray chr)
{
    return senderToHex(chr);
}

/******************************************************************************/

void MainWindow::serialReadDone()
{
    if (comPort->isHexDisplay) {
        ui->recvTextBrowser->insertPlainText(charToHex(comPort->comData));
    } else {
        ui->recvTextBrowser->insertPlainText(comPort->comData);
    }

    if (ui->autoForwardCheckBox->isChecked()) {
        if (sock->isHexSend) {
            ui->sendTextEditNet->setText(charToHex(comPort->comData));
        } else {
            ui->sendTextEditNet->setText(comPort->comData);
        }

        on_sendPushButtonNet_clicked();
    }

    comPort->comData.clear();
}

void MainWindow::updateComPortUI()
{
    ui->openSerialPortRadioButton->setChecked(comPort->isSerialOpened);
    ui->closeSerialPortRadioButton->setChecked(!comPort->isSerialOpened);
    ui->baudRateComboBox->setDisabled(comPort->isSerialOpened);
    ui->dataBitComboBox->setDisabled(comPort->isSerialOpened);
    ui->checkBitComboBox->setDisabled(comPort->isSerialOpened);
    ui->stopBitComboBox->setDisabled(comPort->isSerialOpened);
}

void MainWindow::on_serialSelectComboBox_currentTextChanged(const QString &arg1)
{
    comPort->changeTo(arg1);
    updateComPortUI();
}

void MainWindow::on_openSerialPortRadioButton_toggled(bool checked)
{
    if ((ui->serialSelectComboBox->count() == 0)) {
        if (checked) {
            ui->closeSerialPortRadioButton->setChecked(true);
            QMessageBox::critical(this, "错误", "没有可用的串口设备！\n请检查设备连接状态然后重启软件。");
        }
        return;
    }

    if (checked) {
        comPort->portOpen();
    } else {
        comPort->portClose();
    }

    updateComPortUI();
}

void MainWindow::on_baudRateComboBox_currentTextChanged(const QString &arg1)
{
    comPort->baudRate = arg1.toInt();
}

void MainWindow::on_dataBitComboBox_currentTextChanged(const QString &arg1)
{
    comPort->dataBit = arg1.toInt();
}

void MainWindow::on_checkBitComboBox_currentIndexChanged(int index)
{
    comPort->checkBit = index;
}

void MainWindow::on_stopBitComboBox_currentIndexChanged(int index)
{
    comPort->stopBit = index;
}

void MainWindow::on_hexDisplayRadioButton_toggled(bool checked)
{
    comPort->isHexDisplay = checked;
    ui->recvTextBrowser->append("\n");
}

void MainWindow::on_hexSendRadioButton_toggled(bool checked)
{
    QByteArray buf;

    comPort->isHexSend = checked;

    if (comPort->isHexSend) {
        buf = displayCharToHex(ui->sendTextEdit->toPlainText().toLatin1());
    } else {
        buf = displayHexToChar(ui->sendTextEdit->toPlainText().toLatin1());
    }
    ui->sendTextEdit->setText(buf);
}

void MainWindow::on_clearRecvPushButton_clicked()
{
    ui->recvTextBrowser->clear();
}

void MainWindow::on_clearSendPushButton_clicked()
{
    ui->sendTextEdit->clear();
}

void MainWindow::on_sendPushButton_clicked()
{
    if (comPort->comPort != Q_NULLPTR) {
        if (!comPort->comPort->isOpen()) {
            comPort->portOpen();
            ui->openSerialPortRadioButton->setChecked(comPort->comPort->isOpen());
        }

        if (comPort->comPort->isOpen()) {
            if (comPort->isHexSend) {
                comPort->comPort->write(senderToHex(ui->sendTextEdit->toPlainText().toLatin1()));
            } else {
                comPort->comPort->write(ui->sendTextEdit->toPlainText().toLatin1());
            }
        }
    } else {
        QMessageBox::critical(this, "Errot", "没有串口设备");
    }
}

void MainWindow::on_recvTextBrowser_textChanged()
{
    if (ui->recvTextBrowser->toPlainText().size() > 50000) {
        ui->recvTextBrowser->clear();
    }

    QTextCursor cursor =  ui->recvTextBrowser->textCursor();
    cursor.movePosition(QTextCursor::End);
    ui->recvTextBrowser->setTextCursor(cursor);
}

/********************************************************************************************/

void MainWindow::socketCountUpdate()
{
    ui->clientsComboBox->clear();

    if (sock->protocol == UDP) {
        ui->clientsComboBox->addItem(sock->udpClient.ip.toString() + ":" + QString::number(sock->udpClient.port));
    } else {
        QTcpSocket *client;

        ui->clientsComboBox->addItem(QString("All clients (%1)").arg(sock->clientList.count()));
        foreach (client, sock->clientList) {
            ui->clientsComboBox->addItem(client->peerAddress().toString() + ":" + QString::number(client->peerPort()));
        }
    }

    ui->disconnectRadioButton->setChecked(!sock->isOnline);
}

void MainWindow::socketReadDone()
{
    if (sock->isHexDisplay) {
        ui->recvTextBrowserNet->insertPlainText(charToHex(sock->tcpData));
    } else {
        ui->recvTextBrowserNet->insertPlainText(sock->tcpData);
    }

    if (ui->autoForwardCheckBox->isChecked()) {
        if (comPort->isHexSend) {
            ui->sendTextEdit->setText(charToHex(sock->tcpData));
        } else {
            ui->sendTextEdit->setText(sock->tcpData);
        }

        on_sendPushButton_clicked();
    }

    sock->tcpData.clear();
}

void MainWindow::on_hexDisplayRadioButtonNet_toggled(bool checked)
{
    sock->isHexDisplay = checked;
    ui->recvTextBrowserNet->append("\n");
}

void MainWindow::on_recvTextBrowserNet_textChanged()
{
    if (ui->recvTextBrowserNet->toPlainText().size() > 50000) {
        ui->recvTextBrowserNet->clear();
    }

    QTextCursor cursor =  ui->recvTextBrowserNet->textCursor();
    cursor.movePosition(QTextCursor::End);
    ui->recvTextBrowserNet->setTextCursor(cursor);
}

void MainWindow::on_clearRecvPushButtonNet_clicked()
{
    ui->recvTextBrowserNet->clear();
}

void MainWindow::on_hexSendRadioButtonNet_toggled(bool checked)
{
    QByteArray buf;

    sock->isHexSend = checked;

    if (sock->isHexSend) {
        buf = displayCharToHex(ui->sendTextEditNet->toPlainText().toLatin1());
    } else {
        buf = displayHexToChar(ui->sendTextEditNet->toPlainText().toLatin1());
    }
    ui->sendTextEditNet->setText(buf);
}

void MainWindow::on_clearSendPushButtonNet_clicked()
{
    ui->sendTextEditNet->clear();
}

void MainWindow::on_sendPushButtonNet_clicked()
{
    if (ui->disconnectRadioButton->isChecked()) {
        ui->connectRadioButton->setChecked(true);
    }

    int uiClientIndex = ui->clientsComboBox->currentIndex();

    if (sock->protocol == UDP) {
        if (sock->isHexSend) {
            sock->udpSock->writeDatagram(senderToHex(ui->sendTextEditNet->toPlainText().toLatin1()), sock->udpClient.ip, sock->udpClient.port);
        } else {
            sock->udpSock->writeDatagram(ui->sendTextEditNet->toPlainText().toLatin1(), sock->udpClient.ip, sock->udpClient.port);
        }
    } else {
        QTcpSocket *client;

        foreach (client, sock->clientList) {
            if (uiClientIndex != 0) {
                if (sock->clientList.indexOf(client) != (uiClientIndex - 1)) {
                    continue;
                }
            }

            if (sock->isHexSend) {
                client->write(senderToHex(ui->sendTextEditNet->toPlainText().toLatin1()));
            } else {
                client->write(ui->sendTextEditNet->toPlainText().toLatin1());
            }
        }
    }
}

void MainWindow::on_connectRadioButton_toggled(bool checked)
{
    ui->protocolSelectComboBox->setDisabled(checked);
    ui->iPComboBox->setDisabled(checked);
    ui->portLineEdit->setDisabled(checked);

    if (checked) {
        sock->ipAddr = ui->iPComboBox->currentText();
        sock->port = ui->portLineEdit->text().toInt();
        sock->socketStart();
    } else {
        sock->socketStop();
    }

    socketCountUpdate();
}

void MainWindow::on_protocolSelectComboBox_currentIndexChanged(int index)
{
    sock->protocol = (NetProtocol)index;
    if (index == 0) { // TCP Server
        ui->ipLabel->setText("本地IP:");
        ui->clientsComboBox->setHidden(false);
        ui->clientsComboBox->setCurrentIndex(0);
        ui->clientsComboBox->setEditable(false);
    } else if (index == 1) { // TCP Client
        ui->ipLabel->setText("远程IP:");
        ui->clientsComboBox->setHidden(true);
    } else { // UDP
        ui->ipLabel->setText("本地IP:");
        ui->clientsComboBox->setHidden(false);
        ui->clientsComboBox->setEditable(true);
        ui->clientsComboBox->clear();
    }
}
